#include "TConstructor.h"


/**--------------------------*/
/**FUNCIONES AUXILIARES**/
/**--------------------------*/

int concatenarClave(char* claveConcatenada, char* clave){
    /* Determina si la concatenacion ya tiene alguna clave */
    if (strlen(claveConcatenada)>0){
        /* Si tiene clave entonces agrega el separador */
        strcat(claveConcatenada, CONCATENADOR_CLAVES_STRING);
    }
    /* Concatena la nueva clave */
    strcat(claveConcatenada, clave);
    /* Retorna codigo de OK */
    return CODIGO_OK;
}

int desconcatenarUltimaClave(char* claveConcatenada){
    /* Contador de posicion de cadena de concatenacion de claves */
    int contadorPosicion;
    /* Ultima posicion en la cual se encontro el separador de claves */
    int posicionUltimaConcatenacion;
    /* Inicializamos ambas en cero */
    contadorPosicion=0;
    posicionUltimaConcatenacion=0;
    /* Se recorre la concatenacion hasta el final */
    while (claveConcatenada[contadorPosicion]!=FIN_CADENA){
        if (claveConcatenada[contadorPosicion]==CONCATENADOR_CLAVES_CARACTER){
            /* Si se encuentra separador se guarda la posicion donde se encontro */
            posicionUltimaConcatenacion=contadorPosicion;
        }
        /* Incrementa la posicion actual */
        contadorPosicion++;
    }
    /* Elimina la ultima concatenacion */
    claveConcatenada[posicionUltimaConcatenacion] = FIN_CADENA;
    /* Devuelve codigo de ok */
    return CODIGO_OK;
}

/**--------------------------*/
/**FUNCIONES AUXILIARES**/
/**--------------------------*/
int Tconstructor_Crear(TConstructor* tc){
    /*variable para los for*/
    int i=0;
    /* Crea la cola de Diccionarios */
    C_Crear(&tc->colaDiccionarios, sizeof(TDiccionario));
    /*Inicializo los demas valores del struct que son fijos*/
    tc->errortweet=TWEET_OK;
    tc->nivelAnidamiento=0;
    for(i=0;i<CANT_CLAVES;i++){
        tc->clavepuesta[i]=FALSE;
    }
    for(i=0;i<MAX_DATO;i++){
        tc->clave[i]='\0';
        tc->valor[i]='\0';
    }
    /*le setteo la cola*/
    Tconstructor_setCola(tc, &tc->colaDiccionarios);
    /* Retorna codigo OK */
    return EXIT_SUCCESS;
}

int Tconstructor_Destruir(TConstructor* tc){
    /* Diccionario que saca de la cola */
    TDiccionario diccionarioCola;

    /* Destruye todos los diccionarios de la cola */
    while ( C_Sacar(&tc->colaDiccionarios, &diccionarioCola) ){
        Tdiccionario_Destruir(&diccionarioCola);
    }
    /* Retorna codigo de ok */
    return EXIT_SUCCESS;
}

int Tconstructor_setCola(TConstructor* tc, TCola* cola){
    /* Aca cuando se setea la cola de diccionarios, si
       anteriormente hay una cola se deberian liberar todos
       los recursos de la cola anterior o no?? */

    /* Copia la cola pasada por parametro a la cola del
       TConstructor */
    memcpy(&tc->colaDiccionarios, cola, sizeof(TCola));
    /* Retorna codigo de Ok */
    return EXIT_SUCCESS;
}

int Tconstructor_eventoOcurrido(TConstructor* tc, int evento, void* dato){
    /*evito hacer laburo al pedo si ya hubo un error en el tweet*/
    if((!tc->errortweet)||(tc->errortweet==CLAVE_INVALIDA)){
        /*si me paso una clave entro aca*/
        if(evento==CB_CLAVE){
            /*casteo el dato*/
            char* datoChar = (char*)dato;
            /*agrego el campo al tc*/
            strcpy(tc->clave, datoChar);

            if(tc->nivelAnidamiento>1){
                concatenarClave(tc->claveaconcatenar, tc->clave);
                strcpy(tc->clave,tc->claveaconcatenar);
                tc->errortweet=TWEET_OK;
            }

            if(!tc->errortweet){/**todo iria aca adentro*/}

            /*fijarme si la clave es de alguno de las validas*/
            /*"id_str";"text";"retweeted";"created_at";"in_reply_to_status_id_str";"in_reply_to_screen_name";"source";"user|screen_name";"user|lang"*/
            if( strcmp(tc->clave, "id_str")==0 ){ /*veo que no se repitan las claves. hago un array de booleans para verificarlo?*/
                /*reviso si ya estaba esta clave*/
                if(tc->clavepuesta[0]==TRUE){ /*se inicializan en false*/
                    /*ERROR*/
                    tc->errortweet=CLAVE_REPETIDA;
                }
                else{
                    tc->clavepuesta[0]=TRUE; /*si no estaba, ahora esta*/
                }
            }
            else if( strcmp(tc->clave, "text")==0 ){
                /*reviso si ya estaba esta clave*/
                if(tc->clavepuesta[1]==TRUE){ /*se inicializan en false*/
                    /*ERROR*/
                    tc->errortweet=CLAVE_REPETIDA;
                }
                else{
                    tc->clavepuesta[1]=TRUE; /*si no estaba, ahora esta*/
                }
            }
            else if( strcmp(tc->clave, "retweeted")==0 ){
                /*reviso si ya estaba esta clave*/
                if(tc->clavepuesta[2]==TRUE){ /*se inicializan en false*/
                    /*ERROR*/
                    tc->errortweet=CLAVE_REPETIDA;
                }
                else{
                    tc->clavepuesta[2]=TRUE; /*si no estaba, ahora esta*/
                }
            }
            else if( strcmp(tc->clave, "created_at")==0 ){
                /*reviso si ya estaba esta clave*/
                if(tc->clavepuesta[3]==TRUE){ /*se inicializan en false*/
                    /*ERROR*/
                    tc->errortweet=CLAVE_REPETIDA;
                }
                else{
                    tc->clavepuesta[3]=TRUE; /*si no estaba, ahora esta*/
                }
            }
            else if( strcmp(tc->clave, "in_reply_to_status_id_str")==0 ){
                /*reviso si ya estaba esta clave*/
                if(tc->clavepuesta[4]==TRUE){ /*se inicializan en false*/
                    /*ERROR*/
                    tc->errortweet=CLAVE_REPETIDA;
                }
                else{
                    tc->clavepuesta[4]=TRUE; /*si no estaba, ahora esta*/
                }
            }
            else if( strcmp(tc->clave, "in_reply_to_screen_name")==0 ){
                /*reviso si ya estaba esta clave*/
                if(tc->clavepuesta[5]==TRUE){ /*se inicializan en false*/
                    /*ERROR*/
                    tc->errortweet=CLAVE_REPETIDA;
                }
                else{
                    tc->clavepuesta[5]=TRUE; /*si no estaba, ahora esta*/
                }
            }
            else if( strcmp(tc->clave, "source")==0 ){
                /*reviso si ya estaba esta clave*/
                if(tc->clavepuesta[6]==TRUE){ /*se inicializan en false*/
                    /*ERROR*/
                    tc->errortweet=CLAVE_REPETIDA;
                }
                else{
                    tc->clavepuesta[6]=TRUE; /*si no estaba, ahora esta*/
                }
            }
            else if( strcmp(tc->clave, "user|screen_name")==0 ){
                /*reviso si ya estaba esta clave*/
                if(tc->clavepuesta[7]==TRUE){ /*se inicializan en false*/
                    /*ERROR*/
                    tc->errortweet=CLAVE_REPETIDA;
                }
                else{
                    tc->clavepuesta[7]=TRUE; /*si no estaba, ahora esta*/
                }
            }
            else if( strcmp(tc->clave, "user|lang")==0 ){
                /*reviso si ya estaba esta clave*/
                if(tc->clavepuesta[8]==TRUE){ /*se inicializan en false*/
                    /*ERROR*/
                    tc->errortweet=CLAVE_REPETIDA;
                }
                else{
                    tc->clavepuesta[8]=TRUE; /*si no estaba, ahora esta*/
                }
            }
            else{
                /*ERROR*/
                tc->errortweet=CLAVE_INVALIDA;
            }
        }
        /*si me paso un string entro aca*/
        else if(evento==CB_STRING){
            /*defino una variable int que voy a usar mas abajo en un for*/
            int i=0;
            if(tc->errortweet==CLAVE_INVALIDA){
                tc->errortweet=VALOR_INVALIDO;/*le pongo este error por poner alguno distinto asi sale*/
            }
            else{
                /*me fijo si antes del valor habia una clave*/
                if(!tc->clave){  /*o sea que no habia clave para este valor*/
                    /*ERROR, falta de clave. no estoy seguro de que se pueda dar este error*/
                    tc->errortweet=FALTA_CLAVE;
                }
                else{ /*me fijo si para esa clave vale este tipo de dato*/

                    if(tc->nivelAnidamiento>1){
                        desconcatenarUltimaClave(tc->claveaconcatenar);
                    }

                    if( strcmp(tc->clave, "retweeted")==0 ){
                        /*ERROR, tipo de valor invalido para esta clave*/
                        tc->errortweet=VALOR_INVALIDO;
                    }
                    else{
                        /*es valido*//*casteo y guardo en el diccionario*/
                        char* datoChar = (char*)dato;
                        strcpy(tc->valor, datoChar);
                        /**printf("clave: %s;valor: %s\n",tc->clave,tc->valor);**/
                        /*llamo al TDIccionario_Colocar*/
                        TDiccionario_colocar(&tc->Diccionario, tc->clave, tc->valor);
                        /*reseteo los valores de clave y valor*/
                        for(i=0;i<MAX_DATO;i++){
                            tc->clave[i]='\0';
                            tc->valor[i]='\0';
                        }
                    }
                }
            }
        }
        /*si me paso un boolean entro aca*/
        else if((evento==CB_TRUE)||(evento==CB_FALSE)){
            /*defino una variable int que voy a usar mas abajo en un for*/
            int i=0;
            if(tc->errortweet==CLAVE_INVALIDA){
                tc->errortweet=VALOR_INVALIDO;/*le pongo este error por poner alguno distinto asi sale*/
            }
            else{
                /*me fijo si antes del valor habia una clave*/
                if(!tc->clave){  /*o sea que no habia clave para este valor*/
                    /*ERROR, falta de clave. no estoy seguro de que se pueda dar este error*/
                    tc->errortweet=FALTA_CLAVE;
                }
                else{ /*me fijo si para esa clave vale este tipo de dato*/

                    if(tc->nivelAnidamiento>1){
                        desconcatenarUltimaClave(tc->claveaconcatenar);
                    }

                    if( strcmp(tc->clave, "retweeted")==0 ){
                        /*es valido*//*casteo y guardo en el diccionario*/
                        char* datoChar = (char*)dato; /*lo paso como un string porque sino no se puede guardar*/
                        strcpy(tc->valor, datoChar);
                        /**printf("clave: %s;valor: %s\n",tc->clave,tc->valor);**/
                        /*llamo al TDIccionario_Colocar*/
                        TDiccionario_colocar(&tc->Diccionario, tc->clave, tc->valor);
                        /*reseteo los valores de clave y valor*/
                        for(i=0;i<MAX_DATO;i++){
                            tc->clave[i]='\0';
                            tc->valor[i]='\0';
                        }
                    }
                    else{
                        /*ERROR, tipo de valor invalido para esta clave*/
                        tc->errortweet=VALOR_INVALIDO;
                        }
                }
            }
        }
        /*si me paso un numero entro aca*/
        else if(evento==CB_NUMERO){
            /*defino una variable int que voy a usar mas abajo en un for*/
            int i=0;
            if(tc->errortweet==CLAVE_INVALIDA){
                tc->errortweet=VALOR_INVALIDO;/*le pongo este error por poner alguno distinto asi sale*/
            }
            else{
                /*me fijo si antes del valor habia una clave*/
                if(!tc->clave){  /*o sea que no habia clave para este valor*/
                    /*ERROR, falta de clave. no estoy seguro de que se pueda dar este error*/
                    tc->errortweet=FALTA_CLAVE;
                }
                else{ /*me fijo si para esa clave vale este tipo de dato*/

                    if(tc->nivelAnidamiento>1){
                        desconcatenarUltimaClave(tc->claveaconcatenar);
                    }

                    if( strcmp(tc->clave, "id_str")==0 ){
                        /*es valido*//*casteo y guardo en el diccionario*/
                        char* datoChar = (char*)dato; /*lo paso como un string porque sino no se puede guardar*/
                        strcpy(tc->valor, datoChar);
                        /**printf("clave: %s;valor: %s\n",tc->clave,tc->valor);**/
                        /*llamo al TDIccionario_Colocar*/
                        TDiccionario_colocar(&tc->Diccionario, tc->clave, tc->valor);
                        /*reseteo los valores de clave y valor*/
                        for(i=0;i<MAX_DATO;i++){
                            tc->clave[i]='\0';
                            tc->valor[i]='\0';
                        }
                    }
                    else{
                        /*ERROR, tipo de valor invalido para esta clave*/
                        tc->errortweet=VALOR_INVALIDO;
                    }
                }
            }
        }
        /*si me paso un null entro aca*/
        else if(evento==CB_NULL) {
           /*defino una variable int que voy a usar mas abajo en un for*/
            int i=0;
            if(tc->errortweet==CLAVE_INVALIDA){
                tc->errortweet=VALOR_INVALIDO;/*le pongo este error por poner alguno distinto asi sale*/
            }
            else{
                /*me fijo si antes del valor habia una clave*/
                if(!tc->clave){  /*o sea que no habia clave para este valor*/
                    /*ERROR, falta de clave. no estoy seguro de que se pueda dar este error*/
                    tc->errortweet=FALTA_CLAVE;
                }
                else{ /*null vale para todas las claves*/
                    char* datoChar;

                    if(tc->nivelAnidamiento>1){
                        desconcatenarUltimaClave(tc->claveaconcatenar);
                    }

                    /*es valido*//*casteo y guardo en el diccionario*/
                    datoChar = (char*)dato;
                    strcpy(tc->valor, datoChar);
                    /**printf("clave: %s;valor: %s\n",tc->clave,tc->valor);**/
                    /*llamo al TDIccionario_Colocar*/
                    TDiccionario_colocar(&tc->Diccionario, tc->clave, tc->valor);
                    /*reseteo los valores de clave y valor*/
                    for(i=0;i<MAX_DATO;i++){
                        tc->clave[i]='\0';
                        tc->valor[i]='\0';
                    }
                }
            }
        }
        /*si me paso un '{' entro aca*/
        else if(evento==CB_COMIENZA_OBJETO){
            /*creo un diccionario nuevo, solo si es la llave q abre el objeto principal*/
            if(tc->nivelAnidamiento==0){
                TDiccionario_Crear(&tc->Diccionario);
            }
            /*hago algo mas??*//*no setteo nada, la cola sigue siendo la misma, se borro el diccionario*/

            /**version renovada*/
            tc->nivelAnidamiento++;
            strcpy(tc->claveaconcatenar,tc->clave);
        }
    }
    /*si me paso un '}' entro aca*/
    if(evento==CB_TERMINA_OBJETO){
        /*defino una variable int que voy a usar mas abajo en un for*/
        int i=0;

        if(tc->nivelAnidamiento>1){
            desconcatenarUltimaClave(tc->claveaconcatenar);
        }
        tc->nivelAnidamiento--;

        /*me fijo que todos los elementos del array clavepuesta esten en true, sino no es valido el tweet*/
        if(tc->nivelAnidamiento==0){
            for(i=0;i<CANT_CLAVES;i++){
                if(tc->clavepuesta[i]==FALSE){
                    /*ERROR, faltan claves en el tweet*/
                    tc->errortweet=FALTAN_CLAVES;
                }
                else{ /*sino aprovecho y reseteo los valores de clavepuesta, para el proximo tweet*/
                    tc->clavepuesta[i]=FALSE;
                }
            }
            /*me fijo que el tweet sea valido, sino no agrega el diccionario a la cola*/
            if(!tc->errortweet){
                /*agrego el diccionario a la cola*/
                C_Agregar(&tc->colaDiccionarios, &tc->Diccionario);
            }
            /*reinicio los valores fijos del struct(excepto clavepuesta que ya lo hice mas arriba)*/
            tc->errortweet=TWEET_OK;
            for(i=0;i<MAX_DATO;i++){
                tc->clave[i]='\0';
                tc->valor[i]='\0';
            }
        }
    }
    /*si me paso un '[' o ']' entro aca*/
    else if((evento==CB_COMIENZA_ARRAY)||(evento==CB_TERMINA_ARRAY)){
        /*tiro error directamente*/
        /*ERROR, tipo de valor invalido para esta clave, es invalido para cualquiera*/
        tc->errortweet=VALOR_INVALIDO;
    }
    return EXIT_SUCCESS;
}

/*--------------------------------------------------------------------*/
/*--------------------------------------------------------------------*/
/*funcion para pasar al main despues*/
int Tconstructor_ArmarLista(TConstructor* tc, TListaSimpleOrdenada* listaCampos){
    /*defino otro valor para comparar*/
    char valor2[256];
    char aux[256];
    /*creo un diccionario nuevo*/
    TDiccionario Diccionario;
    TDiccionario_Crear(&Diccionario);
    /*le asigno el campo nombre a la clave porque es el parametro de ordenamiento para mi lista*/
    strcpy(tc->clave,"user|screen_name");
    /*pongo el primer elemento en la lista*/
    if(!(C_Vacia(tc->colaDiccionarios)==0)){
        /*Saco el diccionario de la cola*/
        C_Sacar(&tc->colaDiccionarios, &Diccionario);
        /*obtengo y guardo el valor de Diccionario[user|screen_name]*/
        TDiccionario_obtener(&Diccionario,tc->clave,tc->valor);

        TDiccionario_obtener(&Diccionario,"id_str",aux);

        /*pongo el nombre en la lista*/
        lso_Insertar(listaCampos,tc->valor);
        /*destruyo el diccionario auxiliar*/
        Tdiccionario_Destruir(&Diccionario);

        /*voy sacando los elementos de la lista de a uno hasta que quede vacia*/
        while(!(C_Vacia(tc->colaDiccionarios)==0)){
            /*creo un diccionario nuevo*/
            TDiccionario_Crear(&Diccionario);
            /*saco el elemento del tope*/
            C_Sacar(&tc->colaDiccionarios, &Diccionario);
            /*obtengo y guardo el valor de Diccionario[user|screen_name] en otro campo*/
            TDiccionario_obtener(&Diccionario,tc->clave,valor2);
            /*pongo el nombre en la lista*/
            lso_Insertar(listaCampos,valor2);
            /*destruyo el diccionario auxiliar*/
            Tdiccionario_Destruir(&Diccionario);
        }
    }
    return EXIT_SUCCESS;
}
